package com.tx.admin.security.service.impl;

import java.awt.image.BufferedImage;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.google.code.kaptcha.Producer;
import com.tx.admin.core.service.TreeService;
import com.tx.admin.core.anno.Rbac;
import com.tx.admin.core.anno.RbacMapping;
import com.tx.admin.modules.base.entity.RbacEntity;
import com.tx.admin.core.exception.SuperException;
import com.tx.admin.core.po.LoginPo;
import com.tx.admin.modules.rbac.entity.DataFunctionEntity;
import com.tx.admin.modules.rbac.entity.DataPermissionEntity;
import com.tx.admin.modules.rbac.entity.DepartmentEntity;
import com.tx.admin.modules.rbac.entity.RoleEntity;
import com.tx.admin.modules.rbac.entity.UserEntity;
import com.tx.admin.modules.rbac.service.DataFunctionService;
import com.tx.admin.modules.rbac.service.DataPermissionService;
import com.tx.admin.modules.rbac.service.DepartmentService;
import com.tx.admin.modules.rbac.service.RoleService;
import com.tx.admin.modules.rbac.service.RoleUserService;
import com.tx.admin.modules.rbac.service.UserService;
import com.tx.admin.security.constant.SecurityConstant.DataScope;
import com.tx.admin.security.service.MailService;
import com.tx.admin.security.service.Md5Service;
import com.tx.admin.security.service.SecurityService;
import com.tx.admin.util.web.SessionUtil;

import lombok.extern.slf4j.Slf4j;


@Slf4j
@Component
 class SecurityServiceImpl implements SecurityService{

	@Autowired
	private UserService userService;
	
	@Autowired
	private MailService mailService;
	
	@Autowired
	private Md5Service md5Service;
	@Autowired
	private RoleService roleService;
	@Autowired
	private DepartmentService departmentService;
	
	@Autowired
	private RoleUserService roleUserService;
	
	@Autowired
	private DataFunctionService dataFunctionService;
	@Autowired
	private DataPermissionService dataPermissionService;
	
	static enum SecurityServiceEnum{
		createVerifyCode,
		VerifyCodeByMail,
		user,
		department,
	}
	
	@Autowired
	private Producer producer;
	
	@Override
	public UserEntity findByUserName(String userName) {
		// TODO Auto-generated method stub
		return userService.findByUserName(userName);
	}

	@Override
	public void createVerifyCodeByMail(LoginPo loginParams)  {
		// TODO Auto-generated method stub
		this.checkCode(SecurityServiceEnum.createVerifyCode, loginParams.getVerifyCode());
		String text = this.producer.createText();
		SessionUtil.set(SecurityServiceEnum.VerifyCodeByMail,text);
		this.mailService.sendAutdCode(loginParams.getUserName(), text);
	}

	@Override
	public void updatePasswordByMail(LoginPo loginParams) {
		// TODO Auto-generated method stub
		this.checkCode(SecurityServiceEnum.VerifyCodeByMail, loginParams.getVerifyCode());
		UserEntity user = this.userService.findByUserName(loginParams.getUserName());
		if(user == null) {
			SuperException.throwEx("账户不存在");
		}else {
			user.setPassword(loginParams.getPassword());
			this.userService.save(user);
		}
	}

	@Override
	public void logout() {
		// TODO Auto-generated method stub
		Subject subject = SessionUtil.getSubject();
		if(subject.isAuthenticated()) {
			subject.logout();
		}	
	}

	@Override
	public BufferedImage createVerifyCode() {
		// TODO Auto-generated method stub
		String text = this.producer.createText();
		SessionUtil.set(SecurityServiceEnum.createVerifyCode,text);
		return this.producer.createImage(text);
	}
	
	private void checkCode(SecurityServiceEnum key,String code) {
		String text = SessionUtil.get(key);
		if(StringUtils.isBlank(text)) {
			SuperException.throwEx("请获取验证码");
		}else if(!StringUtils.equals(text, code)) {
			SuperException.throwEx("验证码错误");
		}
	}

	@Override
	public void runUser(String userName) {
		// TODO Auto-generated method stub
		Subject subject = SessionUtil.getSubject();
		PrincipalCollection principalCollection = new SimplePrincipalCollection(userName,"UserRealm");
		subject.runAs(principalCollection);
	}

	@Override
	public void flushRole() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public String getToken() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void login(LoginPo params) {
		// TODO Auto-generated method stub
		Subject subject = SessionUtil.getSubject();
		if(subject.isAuthenticated()) {
			return ;
		}	
		UserEntity entity = this.userService.findByUserName(params.getUserName());
		if(entity == null) {
			SuperException.throwEx("账户不存在");
		}
		UserEntity user = new UserEntity();
		user.setUserName(params.getUserName());
		user.setPassword(params.getPassword());
		user.setSalt(entity.getSalt());
		this.md5Service.hashUser(user);
	
		AuthenticationToken  token = new UsernamePasswordToken(user.getUserName(),user.getPassword());
		subject.login(token);
		DepartmentEntity department =  this.departmentService.findById(entity.getDepartmentId());
		
		SessionUtil.set(SecurityServiceEnum.user,entity);
		SessionUtil.set(SecurityServiceEnum.department,department);
		
	}

	
	
	
	@Override
	public void queryRbacEntity(RbacEntity entity, Rbac rbac, RbacMapping rbacMapping) {
		// TODO Auto-generated method stub
		Set<String> filterUser = new TreeSet<>(),
				filterDepartment=new HashSet<>();
				String rbacKey = rbac.value()+"-"+rbacMapping.value();
			
				this.getDataPermission().forEach(dataPermissionEntity -> {
					if(StringUtils.isBlank(dataPermissionEntity.getDataScope())) {
						return;
					}else if(!dataPermissionEntity.getId().contains(rbacKey)) {
						log.info("过滤权限范围:"+rbacKey);
						return;
					}
					log.info("权限设置:"+rbacKey);
					String dataScope =dataPermissionEntity.getDataScope();
					Set<String> set = this.getController(dataPermissionEntity);
					if(DataScope.user_none.name().equals(dataScope)) {
						filterUser.addAll(set);
					}else if(DataScope.user_one.name().equals(dataScope)) {
						filterUser.addAll(set);
					}else if(DataScope.department_one.name().equals(dataScope)) {
						filterDepartment.addAll(set);
					}else if(DataScope.department_tree.name().equals(dataScope)) {
						filterDepartment.addAll(set);
					}else {
						
					}
			
				});
			
				entity.setFilterUser(filterUser);
				entity.setFilterDepartment(filterDepartment);
			
	}

	@Override
	public void saveRbacEntity(RbacEntity entity,Rbac rbac , RbacMapping rbacMapping) {
		// TODO Auto-generated method stub
		String userId = this.getUser().getId();
		String departmentId = this.getDepartment().getId();
		if(entity.getCrtUser() == null) {
			entity.setCrtUser(userId);
		}
		if(entity.getCrtDepartment() == null) {
			entity.setCrtDepartment(departmentId);
		}
		entity.setUptUser(userId);
		entity.setUptDepartment(departmentId);
		this.queryRbacEntity(entity, rbac, rbacMapping);
	
	}

	@Override
	public List<RoleEntity> getRoleAll() {
		// TODO Auto-generated method stub
		UserEntity user = this.getUser();
		return this.roleUserService.findByUser(user).stream().map(val -> {
			return val.getRole();
		}).collect(Collectors.toList());
	}

	@Override
	public List<DataFunctionEntity> getDataFunction() {

		List<String> ids = new LinkedList<>();
		StringBuffer sb = new StringBuffer();
		this.getRoleAll().forEach(val -> {
			ids.addAll(val.getDataFunctionIds());
		});
		return this.dataFunctionService.findByIds(ids);
	}

	@Override
	public List<DataPermissionEntity> getDataPermission() {

		List<String> ids = new LinkedList<>();
		this.getRoleAll().forEach(val -> {
			ids.addAll(val.getDataPermissionIds());
		});
		return this.dataPermissionService.findByIds(ids);
	}
	
	private Set<String> getController(DataPermissionEntity dataPermissionEntity) {
		Set<String> set = new HashSet<>();
		String dataScope = dataPermissionEntity.getDataScope();
		if(DataScope.user_none.name().equals(dataScope)) {
			
		}else if(DataScope.user_one.name().equals(dataScope)) {
			String id = this.getUser().getId();
			set.add(id);
		}else if(DataScope.department_one.name().equals(dataScope)) {
			String id = this.getDepartment().getId();
			set.add(id);
		}else if(DataScope.department_tree.name().equals(dataScope)) {
			DepartmentEntity parent = this.getDepartment(); 
			DepartmentEntity tree = this.departmentService.findByIdBuildChildren(parent.getId());
			List<DepartmentEntity> list =new LinkedList<>();
			TreeService.treeToLink(tree, list);
			list.forEach(val -> {
				set.add(val.getId());
			});
		}else {
				log.debug("异常枚举:"+dataPermissionEntity.getId());
		}
	
		return set;
	}

	public UserEntity getUser() {
		Subject subject = SessionUtil.getSubject();
		if(!subject.isAuthenticated()) {
			SuperException.throwEx("请登陆!");
		}
		UserEntity user = SessionUtil.get(SecurityServiceEnum.user);
		if(user == null) {
			SuperException.throwEx("用户不存在!");
		}
		return user;
	
	}
	
	public DepartmentEntity  getDepartment() {
		return SessionUtil.get(SecurityServiceEnum.department);
	}


}
